﻿using ManagementApi.Models.BankTransfer;
using Modules;
using Modules.BankSpecialAccount;
using Modules.BankSpecialAccount.Entitys;
using Modules.BankSpecialAccount.EventModules;
using Modules.Payroll;
using Modules.Person;
using PmSoft;
using PmSoft.ApplicationContext;
using PmSoft.Events;
using PmSoft.Exceptions;

namespace ManagementApi.Services.BankTransfer;

/// <summary>
/// 银行转账服务
/// </summary>
[UseDI(ServiceLifetime.Scoped)]
public class BankTransferService
{
    private readonly IConfiguration configuration;
    private readonly string bankTransferServiceUrl;
    private readonly WagePayrollService wagePayrollService;
    private readonly IApplicationContext applicationContext;
    private readonly BankSpecialAccountService projectSpecialAccountService;
    private readonly IEventBus eventBus;
    private readonly BankTransferConnection bankTransferConnection;
    private readonly WagePayrollLogService payrollLogService;
    private readonly PersonService personService;

    /// <summary>
    /// </summary>
    public BankTransferService(IConfiguration configuration, WagePayrollService wagePayrollService, IApplicationContext applicationContext, BankSpecialAccountService projectSpecialAccountService, IEventBus eventBus, BankTransferConnection bankTransferConnection, WagePayrollLogService payrollLogService, PersonService personService)
    {
        this.configuration = configuration;
        this.bankTransferServiceUrl = configuration.GetValue<string>("BankTransferService") ?? string.Empty;
        this.applicationContext = applicationContext;
        this.wagePayrollService = wagePayrollService;
        this.projectSpecialAccountService = projectSpecialAccountService;
        this.eventBus = eventBus;
        this.bankTransferConnection = bankTransferConnection;
        this.payrollLogService = payrollLogService;
        this.personService = personService;
    }

    /// <summary>
    /// 创建批量代发批次
    /// </summary>
    /// <returns></returns>
    /// <exception cref="BusinessException"></exception>
    public async Task CreateBatchSalaryPaymentAsync(WagePayroll wagePayroll, IEnumerable<WagePayrollDetail> details, BankSpecialAccountInfo account)
    {
        if (wagePayroll == null) throw new BusinessException("工资单信息不能为空");
        if (wagePayroll.HasCreateBatch && wagePayroll.WageStatus == PayrollConstants.代发状态.未发放) throw new BusinessException("工资单信息不能为空");
        if (!details.Any()) throw new BusinessException("工资明细不能为空");
        var totalAmount = details.Sum(i => i.AmountApplied);
        var balance = await GetAccountBalance(account);
        if (balance < totalAmount) throw new BusinessException("专户余额不足");
        //获取工资单详情中所有的人员信息
        var persons = personService.GetPersons(details.Select(i => i.PersonId));
        //处理发放工资卡的详情，每张卡仅允许一条数据
        List<SalaryPaymentDetail> salaryDetails = new();
        Dictionary<string, int> keyValues = new();
        foreach (WagePayrollDetail detail in details)
        {
            var index = 0;
            if (keyValues.TryGetValue(detail.BankCardNo, out index))
            {
                salaryDetails[index].PayAmount += (detail.AmountApplied ?? 0);
                continue;
            }
            var person = persons.FirstOrDefault(i => i.PersonId == detail.PersonId);
            if (person == null) continue;
            salaryDetails.Add(new SalaryPaymentDetail()
            {
                PayAmount = detail.AmountApplied ?? 0,
                BankCardNo = detail.BankCardNo,
                Name = person.Name,
            });
            keyValues.Add(detail.BankCardNo, salaryDetails.Count - 1);
        }

        CreateBatchSalaryPaymentReq batchSalary = new()
        {
            PayerAcctName = account.Username,
            PayerAcctNo = account.BankNo,
            TranNo = "CR" + DateTime.Now.ToString("yyyyMMddHHmmssfff"),
            Details = salaryDetails,
        };
        var result = await bankTransferConnection.PostBankTransfer<CreateBatchSalaryPaymentResult>(batchSalary, "createBatchPayment") ?? throw new BusinessException("银行转账服务错误，原因:返回信息为空");
        wagePayroll.HasCreateBatch = true;
        wagePayroll.ContractNo = result.ContractNo;
        wagePayroll.BatchNo = result.BatchNo;
        wagePayroll.BankPaymentNo = result.TxnNo;
        wagePayroll.WageStatus = PayrollConstants.代发状态.未发放;
        wagePayrollService.Update(wagePayroll);
        payrollLogService.Create(wagePayroll, PayrollConstants.代发操作类型.创建代发批次, batchSalary.TranNo);
    }

    /// <summary>
    /// 批量代发批次提交
    /// </summary>
    public async Task SubmitBatchSalaryPaymentAsync(WagePayroll wagePayroll, BankSpecialAccountInfo account)
    {
        if (!wagePayroll.HasCreateBatch) throw new BusinessException("工资单还未创建批量代发批次");
        //验证工资单发放金额是否大于专户余额
        var AmountApplied = wagePayroll.AmountApplied;
        var balance = await GetAccountBalance(account);
        if (balance < AmountApplied) throw new BusinessException("专户余额不足");
        SubmitBatchSalaryPaymentReq submitReq = new()
        {
            TranNo = "SU" + DateTime.Now.ToString("yyyyMMddHHmmssfff"),
            ContractNo = wagePayroll.ContractNo,
            BatchNo = wagePayroll.BatchNo,
            TotalAmount = wagePayroll.AmountApplied,
            TotalCount = wagePayroll.NumberPeople,
        };
        var result = await bankTransferConnection.PostBankTransfer<SubmitBatchSalaryPaymentResult>(submitReq, "submitBatchPayment") ?? throw new BusinessException("银行转账服务错误，原因:返回信息为空");
        wagePayroll.ContractNo = result.ContractNo;
        wagePayroll.BatchNo = result.BatchNo;
        wagePayroll.BankPaymentNo = result.TxnNo;
        wagePayroll.HasSubmit = true;
        wagePayroll.WageStatus = PayrollConstants.代发状态.待发放;
        wagePayrollService.Update(wagePayroll);
        payrollLogService.Create(wagePayroll, PayrollConstants.代发操作类型.提交代发批次, submitReq.TranNo);
    }

    /// <summary>
    /// 撤销批量代发批次(提交前可操作)
    /// </summary>
    /// <param name="wagePayroll"></param>
    /// <returns></returns>
    public async Task UnDoBatchSalaryPaymentAsync(WagePayroll wagePayroll)
    {
        if (!wagePayroll.HasCreateBatch) throw new BusinessException("工资单还未创建批量代发批次");
        if (wagePayroll.HasSubmit) throw new BusinessException("工资单已提交银行进入发放流程,无法撤销");
        if (string.IsNullOrEmpty(wagePayroll.ContractNo)) throw new BusinessException("缺少合同号,无法撤销");
        if (string.IsNullOrEmpty(wagePayroll.BatchNo)) throw new BusinessException("缺少批次号,无法撤销");

        CancellBatchPaymentReq submitReq = new()
        {
            TranNo = "RE" + DateTime.Now.ToString("yyyyMMddHHmmssfff"),
            ContractNo = wagePayroll.ContractNo ?? string.Empty,
            BatchNo = wagePayroll.BatchNo ?? string.Empty,
        };
        var result = await bankTransferConnection.PostBankTransfer<bool?>(submitReq, "cancellationBatchPayment") ?? throw new BusinessException("银行转账服务错误，原因:返回信息为空");
        if (result == true)
        {
            wagePayroll.WageStatus = PayrollConstants.代发状态.已撤销;
            wagePayrollService.Update(wagePayroll);
            payrollLogService.Create(wagePayroll, PayrollConstants.代发操作类型.撤销代发批次, submitReq.TranNo);
        }
    }

    /// <summary>
    /// 获取专户余额
    /// </summary>
    /// <returns></returns>
    public async Task<decimal> GetAccountBalance(BankSpecialAccountInfo account)
    {
        AccountBalanceReq submitReq = new()
        {
            AccNo = account.BankNo,
        };
        var result = await bankTransferConnection.PostBankTransfer<dynamic?>(submitReq, "accountBalance") ?? throw new BusinessException("银行转账服务错误，原因:返回信息为空");
        account.Balance = result.balance;
        //修改余额
        eventBus.PublishTo(this, new ReviseBalanceEventArgs(account.Code, account.Balance ?? 0));
        return account.Balance ?? 0;
    }
}